import { useCallback, useEffect, useMemo, useState } from 'react'
import {Input, Select} from 'antd'
import type {ProItemProps, Schema} from '../types'
import { getPinTypeStyle, getTypeTitleBySchema, getItemBySchema } from '../utils'
import {uuid, debounce, InbizIcon} from '@inbiz/utils'
import { ProAry, ProEnum, ProIndexObj, ProObj } from './Pro'
import {SCHEMA_TYPE_TO_CHINESE_MAP} from '../constants'
import css from './index.less'
import { useValueRef } from './context'
const reg = /^[a-zA-Z_][a-zA-Z0-9_]*$/ // 变量名正则
export function ProItem({
    val,
    xpath,
    keyName,
    root = false,
    editor = false,
    onChange
  }: ProItemProps) {
    const options = useMemo(() => {
      return Object.keys(SCHEMA_TYPE_TO_CHINESE_MAP).map(value => {
        return {
          value,
          label: SCHEMA_TYPE_TO_CHINESE_MAP[value as keyof typeof SCHEMA_TYPE_TO_CHINESE_MAP]
        }
      })
    }, [])
    const childItem = useMemo(() => {
      let jsx = <></>
      switch (val?.type) {
        case 'array':
          jsx = <ProAry items={val.items} xpath={xpath} editor={editor} onChange={onChange} />
          break
        case 'object':
          jsx = <ProObj properties={val.properties} xpath={xpath} editor={editor} onChange={onChange}  />
          break
        case 'indexObject':
          jsx = <ProIndexObj properties={val.properties} xpath={xpath} editor={editor} onChange={onChange} />
          break
        case 'enum':
          jsx = <ProEnum items={val.items} editor={editor} onChange={onChange} />
          break
      }
      return jsx
    }, [editor, val])
    const id = useMemo(() => {
      if (keyName) {
        return keyName
      } else {
        return `__inbiz_${uuid()}`
      }
    }, [])
    const [errorMsg, $errorMsg] = useState(() => {
      return !root && (!keyName || keyName.indexOf('__inbiz_') === 0) ?  '字段名不能为空' : ''
    })
    const typeStyle = useMemo(() => {
      return getPinTypeStyle(val.type)
    }, [])
    const [parentKeys, currentKey] = useMemo(() => {
      const arr = xpath.split('/').slice(1);
      return [arr.slice(0, -1), arr[arr.length -1]]
    }, [xpath])
    const valueRef = useValueRef();

    const handleChange = useMemo(() => {
      return debounce({fn: ({value}: {value:string}) => {
        if (!value) {
          $errorMsg('字段名不能为空')
          onChange?.({
            key: 'keyName',
            type: 'update',
            path: xpath,
            value: id,
            id,
            error: true
          })
          return
        }
        if (!reg.test(value)) {
          $errorMsg('字段名有数字、字母、下划线组成，且不能数字开头')
          onChange?.({
            key: 'keyName',
            type: 'update',
            path: xpath,
            value: id,
            id,
            error: true
          })
          return
        }
        const keys = Object.keys(getItemBySchema(parentKeys, valueRef?.current || {} as Schema)?.properties || {});
        if (keys.includes(value)) {
          $errorMsg('字段名重复')
          onChange?.({
            key: 'keyName',
            type: 'update',
            path: xpath,
            id,
            error:true
          })
        } else {
          $errorMsg('');
          onChange?.({
            key: 'keyName',
            type: 'update',
            path: xpath,
            value: value,
            id
          })
        }
      }, delay: 100})
    }, [parentKeys]);
    useEffect(() => {
      return () => {
        onChange?.({
          type: 'destroy',
          path: xpath,
          id,
        })
      }
    }, [])
    const defaultValue = useMemo(() => keyName?.indexOf('__inbiz_') === 0 ? '' : keyName, [])
    return (
      <div key={keyName} className={`${css.item} ${root ? css.rootItem : ''} ${editor ? css.editor : ''}`}>
        <div data-xpath={xpath} className={css.keyName}>
          {
            (editor && keyName !== undefined) ? 
              <>
                <Input 
                  status={errorMsg ? 'error' : undefined} 
                  defaultValue={defaultValue}
                  onChange={(e) => handleChange({value: e.target.value})} 
                  style={{minWidth: 80}}
                  maxLength={50}
                /> 
                {errorMsg && <span className={css.errorMsg}>{errorMsg}</span>}
              </>
                :
              <>
                {!editor && (keyName !== undefined ||  currentKey == ":array") && <span
                  data-not-connect={1}
                  className={`${css.point}`}
                  style={{left: -7, top: 11, borderColor: typeStyle.strokeColor, backgroundColor: typeStyle.fillColor}}
                />}
                {keyName}  
              </>
          }
          
          <span className={css.typeName} style={{color: typeStyle.strokeColor}}>
            {
              editor ? <Select style={{width: 80}} options={options} defaultValue={val.type} onChange={(value) => onChange?.({
                key: 'type',
                type: 'update',
                path: xpath,
                value: value,
                error: !!errorMsg,
                id
              })} /> : 
              (getTypeTitleBySchema(val))
            }
          </span>
          {
            editor && currentKey != ":array" && !root && <InbizIcon className={css.delete} type="icon-ic-tree-huishouzhan" onClick={() => {
              onChange?.({
                type: 'delete',
                path: xpath,
              })
            }} />
          }
        </div>
        {childItem}
      </div>
    )
  }